#!/usr/bin/env python
# -*- coding: utf-8 -*-

u'''
PyProxySwitch is a cross-platform proxy switcher based on 3proxy ,polipo and IP Relay to fast
change proxy for browsers(Firefox,IE, etc.) and other Internet applications,
writen in Python and wxPython.

Welcom to send me your feedback if you feel it useful'''


__author__= 'Kder'
__copyright__ = 'Copyright 2009-2010 Kder'
__credits__ = ['Kder']

__version__ = '1.1.1'
__date__ = '2010-8-7'
__maintainer__ = "Kder"
__email__ = '<kderlin (#) gmail dot com>'
__url__ = 'http://www.kder.info'
__license__ = 'Apache License, Version 2.0'
__status__ = 'Beta'


import sys
import os
import subprocess
import time
import wx
import codecs
import locale
#if os.name == 'nt':
#    import ctypes
#    import win32api
#    import win32gui
SYS_ENCODING = locale.getdefaultlocale()[1]
if 'PyProxySwitch.exe' in sys.path[0]:
    PROGRAM_PATH = os.path.join(os.path.dirname(sys.path[0]), '..').decode(SYS_ENCODING) #.encode('utf-8')
else:
    PROGRAM_PATH = os.path.join(sys.path[0], '..').decode(SYS_ENCODING)
    
#print type(PROGRAM_PATH),os.path.dirname(sys.path[0])
sys.path.append(os.path.join(PROGRAM_PATH, 'src'))
sys.path.append(os.path.join(PROGRAM_PATH, 'cfg'))
reload(sys)
sys.setdefaultencoding('utf-8') #这一行的设置导致了在cmd = eval(CMD_OPEN)中，
                                #直接输出没问题，放到列表中就出错了

#~ import config
import pyetc
config = pyetc.load(os.path.join(PROGRAM_PATH, 'cfg', 'PPS.conf'))
LANG_CONF = config.LANG_CONF
LANG_SET = {'CN' : {'MENU_ABOUT':u'关于',
            'doc':u'''PyProxySwitch是一个跨平台的代理切换程序，用3proxy/polipo/IP Relay作为本地代理/转发器，可以快速切换浏览器（Firefox、IE等）和其他的网络应用程序的代理设置''',
            'MENU_EXIT':u'退出',
            'Website':u'\n作者网站: ',
            'Version':  u'版本 : ',
            'TITLE_ABOUT':u'关于',
            
            },
             'EN':{
                   'MENU_ABOUT':u'&About',
                   'doc':__doc__,
                   'MENU_EXIT':u'&Exit',
                   'Website':u'\nWebsite: ',
                   'Version':  u'Version : ',
                   'TITLE_ABOUT':u'About',
                   }
            }

#print sys.getdefaultencoding() # 
#print LANG_SET[LANG_CONF]['MENU_EXIT']


class TBIcon(wx.TaskBarIcon):

    TBMENU_CLOSE = wx.NewId()
    TBMENU_ABOUT = wx.NewId()    
    pid = None

    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame
        try:        
        # Set the image
            # if os.path.exists("PyProxySwitch.exe"):
                # self.icon = wx.Icon("PyProxySwitch.exe",wx.BITMAP_TYPE_ICO, 16, 16)
            # else:
            self.icon = wx.Icon(os.path.join(PROGRAM_PATH, 'src', 'PyProxySwitch.ico'),
            wx.BITMAP_TYPE_ICO, 16, 16)
#            self.SetIcon(self.icon, TRAY_TIP)
        except Exception,e:
            print e
        self.imgidx = 1

#        global CFG,ITEM,PORT
        # resume last proxy setting  r close_fds=True
        ITEM = LAST
        PORT = ''
        for i in CFG:
            CFG[i].append(wx.NewId())
#            if CFG[i][-1] == 1:
#            if i == LAST:
#            if i == LAST:#以往用的是CFG[i][0]来储存菜单项名称的，现改用i
                # Set tray icon
        self.SetIcon(self.icon, LAST + TRAY_TIP)
        if CMD == 'ip_relay':
            #根据上次退出时记录的代理项目，读取对应的ip和端口
            ITEM = CFG[LAST][0]
            PORT = CFG[LAST][1] 
            
            if LAST not in CFG:
                self.SetIcon(self.icon, ITEM + TRAY_TIP)
            else:
                self.SetIcon(self.icon, LAST + TRAY_TIP)
        try:
		    
            cmd_str = prepair_command(CMD_OPEN, ITEM, PORT)
#            wx.MessageBox(cmd_str,'debug')
            self.process = wx.Process(self)
            self.process.Redirect()
            self.pid = wx.Execute(unicode(cmd_str), wx.EXEC_ASYNC, self.process)
            # if os.name == 'posix':
                # self.subproc = subprocess.Popen(cmd_decoded)
            # else:
                # self.subproc = launchWithoutConsole(cmd_decoded)
                
        except Exception,e:
            wx.MessageBox(str(e.mro),'debug')
            sys.stderr.write(str(e))
#            self.Kill()
#            self.Destroy()
#            sys.exit(10)
        # self.pid = self.subproc.pid


     
    def CreatePopupMenu(self):
        """
        This method is called by the base class when it needs to popup
        the menu for the default EVT_RIGHT_DOWN event.  Just create
        the menu how you want it and return it from this function,
        the base class takes care of the rest.
        """
        self.menu = wx.Menu()
        self.menu.Append(self.TBMENU_CLOSE,   LANG_SET[LANG_CONF]['MENU_EXIT'])
        self.menu.Append(self.TBMENU_ABOUT,  LANG_SET[LANG_CONF]['MENU_ABOUT'])
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
        self.Bind(wx.EVT_MENU, self.OnTaskBarAbout, id=self.TBMENU_ABOUT)
        self.menu.AppendSeparator()
        # check the menu
        for i in CFG:
            self.menu.Append(CFG[i][-1],i.decode('utf-8'),
                             i.decode('utf-8'), kind=wx.ITEM_CHECK)
            self.Bind(wx.EVT_MENU, self.ProxySwitch, id=CFG[i][-1])
            if i == LAST:# 以前是CFG[i][0]
                self.menu.Check(CFG[i][-1],True)

            else:
                self.menu.Check(CFG[i][-1],False)
        return self.menu

    def ProxySwitch(self,evt):
        '''Switch among proxies by killing old subprocess then opening a new one.'''
        self.Kill()
        menuid = evt.GetId()
#       此处改进：以前用的是label，现在直接用key，更加灵活，label可以自定义了
#        item = self.menu.GetLabel(menuid)
        global LAST
        PORT = ''
        for i in CFG:
#            CFG[i][-1] = 0 以前用的是CFG[i]数组的最后一位作为置标位，现改进为用LAST变量置标
            if CFG[i][-1] == menuid:
                ITEM = CFG[i][0]
                if CMD == 'ip_relay':
                    PORT =  CFG[i][1]
                    sys.stdout.write('%s %s' % (ITEM,CMD))
                LAST = i #纪录最后一次使用的代理名称，以便下次启动时自动恢复
                self.SetIcon(self.icon, i.decode('utf-8') + TRAY_TIP)
        
        time.sleep(0.1)
        
        try:
            cmd_str = prepair_command(CMD_OPEN, ITEM, PORT)
#            print cmd_str
            self.process = wx.Process(self)
            self.process.Redirect()        
            if wx.Platform == '__WXMSW__':
                self.pid = wx.Execute(cmd_str, wx.EXEC_ASYNC, self.process)
            else:
                self.pid = wx.Execute(cmd_str, wx.EXEC_ASYNC|wx.EXEC_MAKE_GROUP_LEADER, self.process)

        except Exception,e:
            self.process = None
            print e.mro
        # if os.name == 'posix':
            # self.subproc = subprocess.Popen(eval(CMD_OPEN))
        # else:
            # self.subproc = launchWithoutConsole(eval(CMD_OPEN))
        # self.pid = self.subproc.pid
#        print self.pid

    def OnTaskBarAbout(self, evt):
        wx.MessageBox(MSG_ABOUT,LANG_SET[LANG_CONF]['TITLE_ABOUT'])

    def Kill(self):
        '''Kill the proxy subprocess'''
        try:
            if self.process:
                wx.Process_Kill(self.pid, wx.SIGKILL)
                self.pid = -1
                self.process = None
            # if os.name == 'posix':
                # subprocess.call([CMD_KILL,str(self.pid+1)])
            # if PY_VER >= 2.6:
                # self.subproc.kill()
            #“subprocess object has no attribute 'kill'” for Python < 2.6
            # if PY_VER < 2.6:
                # subprocess.call([CMD_KILL,str(self.pid)])            
        except Exception,e:
            sys.stderr.write(str(e))
            
    def OnTaskBarClose(self, evt):
        rw_conf('s')
        self.Kill()
        self.Destroy()
        sys.exit(0)


class MainWindow(wx.Frame):

    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, -1, title, size = (-1, -1),
        style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
        try:
            self.tbicon = TBIcon(self)
        except:
            self.tbicon = None


class MyApp(wx.App):

    def OnInit(self):
        wx.InitAllImageHandlers()
        frame = MainWindow(None, -1, "PyProxySwitch")
        return True


def main():
    app = MyApp(0)
    app.MainLoop()

def prepair_command(cmd, ITEM, PORT):
    cmd_decoded = list()
     # CMD is [CMD_BIN, CMD_OPTION, eval(CMD_CFG_FILE)]
    for item in eval(cmd):        
        cmd_decoded.append(item)

    cmd_str = str(" ".join(cmd_decoded)).decode('utf-8')
#    print cmd_str
    return cmd_str

def rw_conf(flg):
    '''Read & save settings with config file'''
    global LAST,CMD,LOCAL_PORT
    CFG_LAST = os.path.join(PROGRAM_PATH, 'cfg', 'last.conf')
    if flg == 's':
        f = codecs.open(CFG_LAST,'w','utf-8') 
#        with open(CFG_LAST,'w') as f:
        f.write(LAST.decode('utf-8'))
        f.close()
#            f.write(str(proxies).replace('],','],\n').replace(', {',',\n{').replace('},','\n},'))

    if flg == 'r':
        CMD = config.CMD
        LOCAL_PORT = config.LOCAL_PORT
#        with open(CFG_LAST,'r') as f:
        f = codecs.open(CFG_LAST,'r','utf-8')
        LAST = f.read().strip()
        f.close()

    return 0


# def launchWithoutConsole(command):#, args = None   + args    .wait()
    # """Launches 'command' windowless and waits until finished"""
    # startupinfo = subprocess.STARTUPINFO()
    # subprocess.STARTF_USESHOWWINDOW = 1
    # startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
   #print command
    # return subprocess.Popen(command, startupinfo=startupinfo)

#def pps_debug_log(str):
#    with codecs.open('debug.log','a','utf-8') as f:
#        f.write(str.decode('utf-8'))

def pps_quote(str):
	return   u'\"%s\"' % str

if __name__ == '__main__':
    # init some vars
    # LOCAL_PORT = PORT = None
    # Read settings
    rw_conf('r')
    
    
    PY_VER = float(sys.version.split(' ')[0][0:3])
    #~ TITLE_ABOUT = 'About'
    MSG_ABOUT = ('PyProxySwitch　　' + LANG_SET[LANG_CONF]['Version'] + __version__ + '\n\n' + LANG_SET[LANG_CONF]['doc'] +
    '\n\nby ' + __author__  + ' ' +  __email__ +  LANG_SET[LANG_CONF]['Website'] + __url__)
    TRAY_TIP = " - PyProxySwitch(" + CMD + ")"
    CFG = eval('config.CFG_' + CMD)
    CMD_CFG_FILE = "os.path.join(PROGRAM_PATH, 'cfg', CMD, ITEM+'.conf')"

    if os.name == 'nt':
        CMD_BIN = pps_quote(os.path.join(PROGRAM_PATH, 'bin', CMD , CMD+ '.exe'))
        # CMD_KILL = 'tskill'
    else:
        CMD_BIN = pps_quote(os.path.join(PROGRAM_PATH, 'bin', CMD , CMD))
        # CMD_KILL = 'kill'         
    if  CMD == 'polipo':
        CMD_OPTION = '-c'
        CMD_OPEN = "[CMD_BIN, CMD_OPTION, pps_quote(eval(CMD_CFG_FILE))]"
    elif CMD == '3proxy':
        CMD_OPEN = "[CMD_BIN, pps_quote(eval(CMD_CFG_FILE))]"
    elif CMD == 'ip_relay':
        CMD_OPEN = "[CMD_BIN,LOCAL_PORT,ITEM,PORT]"
    main()
    
#    if os.name == 'nt' and config.DEBUG == 0:
#        def hidewin():
#            whnd = ctypes.windll.kernel32.GetConsoleWindow()
#            if whnd != 0:
#                ctypes.windll.user32.ShowWindow(whnd, 0)
#                ctypes.windll.kernel32.CloseHandle(whnd)
#            ct = win32api.GetConsoleTitle()
#            hd = win32gui.FindWindow(0,ct)
#            win32gui.ShowWindow(hd,0)
#        hidewin()
        
#    subprocess.call([CMD_KILL,'conime'])
#    os.chdir()
    
#vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
